package xyz.lwm.lazycat.beans;

import lombok.Data;
import xyz.lwm.lazycat.utility.StringUtil;
import xyz.lwm.lazycat.utility.ThrowableUtil;

import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.Objects;

/**
 * 构造方法实例化对象
 *
 * @author lwm
 */
@Data
class InstantiableWithConstructor implements Instantiable {

    private final Constructor<?> constructor;

    // instance of self
    private Object instance;

    @Override
    public Object instantiate(Dependency[] dependsOn, BeanRefs beanRefs) {

        try {

            Object[] args = Arrays.stream(dependsOn) .map(
                    dependency -> dependency.apply(beanRefs)).toArray();
            constructor.setAccessible(true);
            if (instance == null) {
                instance = constructor.newInstance(args);
            }
            return instance;

        } catch (Throwable e) {

            String msg = StringUtil.format("Instantiate {} failed, because {}",
                    constructor.getDeclaringClass().getName(), ThrowableUtil.unwrap(e).getMessage());
            throw new BeansException(msg, e);

        }

    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof InstantiableWithConstructor)) {
            return false;
        }
        InstantiableWithConstructor that = (InstantiableWithConstructor) obj;
        return Objects.equals(constructor, that.constructor);
    }

    @Override
    public String toString() {
        return constructor.getDeclaringClass().getName();
    }

}
